﻿#region copyright
//Copyright 2013 Ramon Ordiales Plaza
//
//This file is part of TrayFastMsg.
//
//    TrayFastMsg is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    TrayFastMsg is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with FastMessage.  If not, see <http://www.gnu.org/licenses/>.
//
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FastMessage
{
    public static class FastMessageLib
    {
        public static readonly int puerto = 9900;
        public static void SendMessage(Message msg){
            using (UdpClient udpClient = new UdpClient())
            {
                Byte[] sendBytes = Encoding.ASCII.GetBytes(msg.DataGram);
                IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), puerto);
                udpClient.Send(sendBytes, sendBytes.Length, RemoteIpEndPoint);
            }
        }
    }
    public class FastMessageReader{
        public bool Debugmode = false;
        private static string _origen;
        public static string Origen { get{
            if (_origen == null) _origen = GetOrigen();
            return _origen;
        } }
        private static string[] _escucha;
        public static bool Loading { get; private set; }
        public static string[] Escucha
        {
            get
            {
                lock (lockescucha)
                {
                    if (_escucha == null) return new string[] { Origen };
                    return (string[])_escucha.Clone();
                }
            }
        }
        private static readonly object lockescucha = new object();
        public static string GetOrigen()
        {
            return GetDominioNombre()[1];
        }
        public static string[] GetDominioNombre()
        {
            var gc = System.Security.Principal.WindowsIdentity.GetCurrent();
            return gc.Name.Split('\\');
        }
        private static void GetEscucha()
        {
            lock (lockescucha)
            {
                if (_escucha != null) return;
            }
            var task = Task.Factory.StartNew(() =>
            {
                var gc = System.Security.Principal.WindowsIdentity.GetCurrent();
                var dominionombre = gc.Name.Split('\\');
                var dominio = dominionombre[0] + "\\";
                var res = new List<string>();
                res.Add(dominionombre[1]);
                var wi = System.Security.Principal.WindowsIdentity.GetCurrent().Groups.Cast<SecurityIdentifier>().Where(w => w.BinaryLength > 12);
                var gr = wi.AsParallel().Select((w) => w.Translate(typeof(NTAccount)).Value).ToList();
                res.AddRange(gr.Where(c => c.StartsWith(dominio)).Select(c => c.Substring(dominio.Length)));
                lock (lockescucha)
                {
                    _escucha = res.ToArray();
                }
            });
        }
        
        private object queuelock = new object();
        private Queue<Message> Mensajes=new Queue<Message>();
        public int NumMensajes{get{
            lock (queuelock)
            {
                return Mensajes.Count;
            }
        }
        }
        public bool HayMensajes { get;private set; }
        public Message GetMensaje()
        {
            lock (queuelock)
            {
                var m=Mensajes.Dequeue();
                if (Mensajes.Count == 0) HayMensajes = false;
                return m;
            }
        }
        public void PutMensaje(Message msg)
        {
            lock (queuelock)
            {
                Mensajes.Enqueue(msg);
                HayMensajes = true;
            }
        }
        
        private int Puerto;
        
        public FastMessageReader()
        {
            Puerto = FastMessageLib.puerto;
            Mensajes = new Queue<Message>();
            GetOrigen();
            GetEscucha();
            var tokensource = new CancellationTokenSource();
            CancellationToken ct = tokensource.Token;
            var Hilo = Task.Factory.StartNew(() =>
                {
                ct.ThrowIfCancellationRequested();
                using (UdpClient udpClient = new UdpClient(Puerto))
                {
                  while (!ct.IsCancellationRequested)
                 {
                      Lectura(udpClient,ct);
                 }
                 udpClient.Close();
                }
             }, ct); 

        }
        private TimeSpan timeToWait = TimeSpan.FromSeconds(1);
        private void Lectura(UdpClient udpClient,CancellationToken ct)
        {
            var asyncResult = udpClient.BeginReceive(null, null);
            while(!ct.IsCancellationRequested){
                var r=asyncResult.AsyncWaitHandle.WaitOne(timeToWait);
                if (r)
                {
                    IPEndPoint remoteEP = null;
                    byte[] receivedData = udpClient.EndReceive(asyncResult, ref remoteEP);
                    var returnData = Encoding.ASCII.GetString(receivedData);
                    var data = returnData.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    var msg = Message.Factory(data);
                    if (msg != null)
                    {
                        if (msg.CheckDestino(Escucha)||Debugmode)
                        {
                            if (Debugmode) msg.Origen += "(" + string.Join(";", msg.Destino) + ")";
                            this.PutMensaje(msg);
                        }
                    }
                        
                    
                    break;
                }
            }
        }
    }
    public class Message{
        public DateTime Fecha{get;set;}
        public string Origen{get;set;}
        public string[] Destino{get;set;}
        public string Texto{get;set;}
        public string DataGram
        {
            get
            {
                return Origen + Environment.NewLine + string.Join(";",Destino) + Environment.NewLine + Texto;
            }
        }
        public Message() { }
        public Message(string origen, string destino, string texto)
        {
            Origen = origen;
            Destino = destino.Split(new char[]{';',','},StringSplitOptions.RemoveEmptyEntries);
            Texto = texto;
            Fecha = DateTime.Now;
        }
        public static Message Factory(string[] data)
        {
            if (data.Length < 3) return null;
            var o = data[0];
            var d = data[1];
            var t = string.Join(Environment.NewLine, data.Skip(2));
            return new Message(o, d, t);
        }
        public bool CheckDestino(string[] Destinos)
        {
           
            return !(string.IsNullOrEmpty(Array.Find(Destino, d => Destinos.Contains(d,StringComparer.OrdinalIgnoreCase))));
        }

    }
}
